#include "zen_game_activity.h"
#include "zen_game_action.h"
#include "zen_game_scene.h"
#include "zen_game_texture.h"
#include "zen_app.h"
#include "zen_ticker.h"
#include "zen_log.h"
#include <vector>
#include <mutex>
#include <queue>
#include <map>

namespace Zen
{
	namespace Game
	{
		class RootNode : public Group
		{
		};

		class Activity__ : public Activity
		{
		protected:
			Point2 mScreenSize{};

			std::shared_ptr<RootNode> mRoot;
			std::shared_ptr<ActivityDelegate> mDelegate;
			std::shared_ptr<TouchDispatcher> mTouchDispatcher;
			std::shared_ptr<ActionDispatcher> mActionDispatcher;
			std::shared_ptr<RenderStack> mDefaultRenderStack;

			Zen::Ticker mFPSTicker;
			int mUpdateCount = 0;
			double mRealFPS = 0;

			double mRunningSeconds; // running Duration
			std::chrono::microseconds mStartTimepoint;
			std::shared_ptr<Zen::Graphics::Engine> mGraphicsEngine;
			std::shared_ptr<Zen::Game::TextureCache> mTextureCache;

		public:
			static std::shared_ptr<Activity__> Only_();

			Activity__();

			virtual ~Activity__();

		public: // override
			virtual void InitDelegate(std::shared_ptr<ActivityDelegate> delegate) override;
			virtual std::shared_ptr<ActivityDelegate> GetDelegate() override;
			virtual Point2 GetScreenSize() override;
			virtual double GetRunningTime() override;
			virtual double GetActivityTime() override;
			virtual double GetRealFPS() override;
			virtual std::shared_ptr<Node> GetRoot() override;

		public:
			virtual void OnLaunch(Zen::Point2 view_size) override;

			virtual void OnResize(Zen::Point2 view_size) override;

			virtual void OnExit() override;

			virtual void OnPause() override;

			virtual void OnResume() override;

		public:
			virtual void OnUpdate() override;

			virtual void OnDraw() override;

			virtual void OnTouchDown(AppTouch const& touch) override;

			virtual void OnTouchMove(AppTouch const& touch) override;

			virtual void OnTouchUp(AppTouch const& touch) override;

			virtual void OnTouchCancel(AppTouch const& touch) override;

			virtual void OnMouseMove(AppMouse mouse) override;

			virtual void OnMouseKeyDown(AppMouse mouse) override;

			virtual void OnMouseKeyUp(AppMouse mouse) override;

			int mMouseKey = 0;

		public:
			Zen::Game::TouchDispatcher* GetTouchDispatcher() override
			{
				return mTouchDispatcher.get();
			}

			Zen::Game::ActionDispatcher* GetActionDispather() override
			{
				return mActionDispatcher.get();
			}

			virtual void InitGraphicsEngine(std::shared_ptr<Zen::Graphics::Engine> engine) override
			{
				mGraphicsEngine = engine;
			}
			virtual std::shared_ptr<Zen::Graphics::Engine> GetGraphicsEngine() override
			{
				return mGraphicsEngine;
			}
		};

	} // namespace Game
} // namespace Zen

namespace Zen
{
	namespace Game
	{
		void Activity__::OnLaunch(Zen::Point2 view_size)
		{
			__Trace(0);

			mScreenSize = view_size;

			mStartTimepoint = Time::Now();
			mRunningSeconds = 0.0;

			if (mGraphicsEngine) mGraphicsEngine->Initialize();
			if (mDelegate) mDelegate->OnLaunch();
		}

		void Activity__::OnResize(Zen::Point2 view_size)
		{
			__Trace(0);

			mScreenSize = view_size;
			if (mDelegate) mDelegate->OnResize();
		}

		void Activity__::OnExit()
		{
			__Trace(0);

			if (mDelegate) mDelegate->OnExit();
		}

		void Activity__::OnPause()
		{
			__Trace(0);

			if (mDelegate) mDelegate->OnPause();
		}

		void Activity__::OnResume()
		{
			__Trace(0);

			if (mDelegate) mDelegate->OnResume();

			mFPSTicker.Tick();
			mRealFPS = 0;
			mUpdateCount = 0;
		}

		void Activity__::OnUpdate()
		{
			auto interval = 1.f / App::Only()->GetFramesPerSecond(); // m_ticker.Tick();

			mRunningSeconds += interval;

			mActionDispatcher->OnUpdate(interval);

			++mUpdateCount;
			if (mUpdateCount == 10)
			{
				mUpdateCount = 0;
				mRealFPS = 10.f / Time::ToSeconds(mFPSTicker.Tick());
			}
		}

		double Activity__::GetRealFPS()
		{
			return mRealFPS;
		}

		void Activity__::OnDraw()
		{
			if (mGraphicsEngine)
			{
				auto interval = 1.f / App::Only()->GetFramesPerSecond();
				mDefaultRenderStack->Reset();
				mRoot->OnReady(mDefaultRenderStack, interval);

				mGraphicsEngine->BeginRender();
				mRoot->OnDraw();
				mGraphicsEngine->EndRender();
			}
			else
			{
				Zen::LogE("No Graphics Engine");
			}
		}

		void Activity__::OnTouchDown(AppTouch const& touch)
		{
			mTouchDispatcher->OnTouchDown(touch);
		}

		void Activity__::OnTouchMove(AppTouch const& touch)
		{
			mTouchDispatcher->OnTouchMove(touch);
		}

		void Activity__::OnTouchUp(AppTouch const& touch)
		{
			mTouchDispatcher->OnTouchUp(touch);
		}

		void Activity__::OnTouchCancel(AppTouch const& touch)
		{
			mTouchDispatcher->OnTouchCancel(touch);
		}
		void Activity__::OnMouseMove(AppMouse mouse)
		{
			if (mMouseKey)
			{
				AppTouch touch;
				touch.no = 0;
				touch.force = 1.f;
				touch.x = mouse.x;
				touch.y = mouse.y;
				mTouchDispatcher->OnTouchMove(touch);
			}
		}
		void Activity__::OnMouseKeyDown(AppMouse mouse)
		{
			mMouseKey |= (int)mouse.button;
			AppTouch touch;
			touch.no = (int)mouse.button;
			touch.force = 1.f;
			touch.x = mouse.x;
			touch.y = mouse.y;
			mTouchDispatcher->OnTouchDown(touch);
		}
		void Activity__::OnMouseKeyUp(AppMouse mouse)
		{
			AppTouch touch;
			touch.no = (int)mouse.button;
			touch.force = 1.f;
			touch.x = mouse.x;
			touch.y = mouse.y;
			mTouchDispatcher->OnTouchUp(touch);
			mMouseKey &= ~(int)mouse.button;
		}
	} // namespace Game
} // namespace Zen

namespace Zen
{
	namespace Game
	{

		std::shared_ptr<Activity__> Activity__::Only_()
		{
			static auto root = std::make_shared<Activity__>();
			return root;
		}

		std::shared_ptr<Activity> Activity::Only()
		{
			return Activity__::Only_();
		}

		Activity__::Activity__()
		{
			mRoot = std::make_shared<RootNode>();
			mTouchDispatcher = std::make_shared<TouchDispatcher>();
			mActionDispatcher = std::make_shared<ActionDispatcher>();
			mDefaultRenderStack = std::make_shared<RenderStack>();
		}

		Activity__::~Activity__()
		{
			mRoot.reset();
		}

		void Activity__::InitDelegate(std::shared_ptr<ActivityDelegate> delegate)
		{
			mDelegate = delegate;
		}

		Point2 Activity__::GetScreenSize()
		{
			return mScreenSize;
		}

		std::shared_ptr<Node> Activity__::GetRoot()
		{
			return mRoot;
		}
		double Activity__::GetRunningTime()
		{
			return mRunningSeconds;
		}
		double Activity__::GetActivityTime()
		{
			return Zen::Time::ToSeconds(Time::Now() - mStartTimepoint);
		}
		std::shared_ptr<ActivityDelegate> Activity__::GetDelegate()
		{
			return mDelegate;
		}

	} // namespace Game
} // namespace Zen
